package scau.cn.component.abstracts;

import java.io.Serializable;

import scau.cn.component.domain.FileN;
import scau.cn.fat.FAT;

public abstract class Disk implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * 名字和长度一共4字节，名字3字节，长度1字节 位运算
	 */
	protected int nameAndLength;
	// （两字节）为文件类型名，这里统一使用.t为文件类型名
	protected short type;

	/**
	 * 为属性，第 0 位表示文件为只读文件，
	 * 第 1 位表示文件为系统文件， 
	 * 第 2 位表示文件为可读、可写的普通文件，
	 * 第3位若为1表示该登记项不是文件的登记项，而是目录的登记项，其余几位闲置未用
	 */
	protected byte attribute;
	// 起始位置
	protected byte start;
	// 唯一可操作的FAT表
	protected FAT fat;
	// 上一级目录
	protected Disk parent; 

	protected abstract boolean modify();

	public abstract boolean delete();


	public int getNameAndLength() {
		return nameAndLength;
	}

	public void setNameAndLength(int nameAndLength) {
		this.nameAndLength = nameAndLength;
	}

	public short getType() {
		return type;
	}

	public void setType(short type) {
		this.type = type;
	}

	public byte getAttribute() {
		return attribute;
	}

	public void setAttribute(byte attribute) {
		this.attribute = attribute;
	}

	public byte getStart() {
		return start;
	}

	public void setStart(byte start) {
		this.start = start;
	}

	public FAT getFat() {
		return fat;
	}

	public void setFat(FAT fat) {
		this.fat = fat;
	}

	public Disk getParent() {
		return parent;
	}

	public void setParent(Disk parent) {
		this.parent = parent;
	}

	// ------------------------------方法-----------------------------------
	/**
	 * 获得文件的操作类型所对应的代码：
	 * 可读可写 ：1 
	 * 只读 ： 0 
	 * 系统文件 ： 2(这个不会存在的)
	 * 注意这个函数是为了方便操作才有的。因为我们在图形界面传入的不可能是一段二进制串
	 * 
	 * @return opType : 操作类型代码
	 * @author 严浩强
	 */
	public int getOpType() {
		int opType;
		if ((this.attribute & 0b00000101) == 4) {
			// 可读可写
			opType = 1;
		} else if ((this.attribute & 0b00000101) == 1) {
			// 只读
			opType = 0;
		} else {
			// 系统文件
			opType = 2;
		}
		return opType;
	}
	
	/**
	 * 修改操作码
	 * @return newOpType : 新的操作码     1 只读 ： 0 系统文件 ： 2(这个不会存在的)
	 * @return opType : 操作类型代码
	 */
	public boolean setOpType(int newOpType) {
		int opType;
		if ((this.attribute & 0b00000101) == 4) {
			// 可读可写
			opType = 1;
		} else if ((this.attribute & 0b00000101) == 1) {
			// 只读
			opType = 0;
		} else {
			// 系统文件
			opType = 2;
		}
		//需要修改的和原来的一样就不需要进行操作
		if (newOpType == opType) {
			return true;
		}
		//需要修改的值进行限定
		else if (newOpType>=0||newOpType<=2) {
			//修改为只读属性
			if(newOpType == 0) {
				this.attribute=(byte) ((this.attribute & 0b11111000) + 1);
			}
			//修改为可读可写
			else if (newOpType == 1) {
				this.attribute=(byte) ((this.attribute & 0b11111000) + 4);
			}
			//修改为系统文件
			else {
				this.attribute=(byte) (this.attribute & 0b11111010);
			}
			System.out.println("Disk中 setOpType, 修改后的属性为：" + this.attribute);
			return true;
		}
		else {
			return false;
		}
		
	}

	/**
	 * 寻找文件的在模拟磁盘中的绝对路径：
	 * 
	 * @return path
	 * @author 严浩强
	 */
	public String findPath() {
		String path = new String(this.getName());
		Disk fileParent = this.getParent();
		while (fileParent != null) {
			path = fileParent.getName() + '/' + path;
			fileParent = fileParent.getParent();
		}
		return path;
	}

	/**
	 * 获得文件或目录的最后一个磁盘块的位置
	 * 
	 * @param fileN
	 * @return start: 最后一个磁盘块的位置
	 * @author 周晓峰，严浩强
	 */
	public int findLastDiskMemory() {
		int start = this.getStart();
		FAT fat = this.getFat();
		int next = fat.getStatus(start);
		while (next != 255) {
			start = next;
			next = fat.getStatus(next);
		}
		return start;
	}

	/**
     * 清空文件或目录的盘块
     * @author 周晓峰，严浩强
     */
    public void clearAllDiskMemory() {
    	int start = this.getStart();
    	FAT fat = this.getFat();
    	int next = fat.getStatus(start);
    	while(next != 255) {
    		fat.setStatus(start, 0);
    		start = next;
    		next = fat.getStatus(next);
    	}
    	this.start= (byte)start;
    }
    
    /**
	 * @param b 修改文件长度
	 */
	public void setLength(byte b) {
		nameAndLength = nameAndLength & 0xFFFFFF00;
		nameAndLength += b;
	}

	/**
	 * @return 获得长度
	 */
	public int getLength() {
		return nameAndLength & 0xFF;
	}
	
	/**
	 * 测试通过
	 */
	public String getName() {
		byte[] bytes = new byte[3];
		int nameAndLength1 = nameAndLength >> 8;
		for (int i = 2; i >= 0; i--) {
			bytes[i] = (byte) (nameAndLength1 & 0x000000ff);
			nameAndLength1 = nameAndLength1 >> 8;
		}
		int name = nameAndLength1 >> 8;
		return new String(bytes);
	}

	/**
	 * 测试通过
	 */
	public void setName(String input) throws Exception {
		byte[] bytes = input.getBytes();
		System.out.println("test"+bytes.toString());
		if (bytes.length > 3) {
			throw new Exception("超过三个字节");
		}
		byte length = (byte) nameAndLength;
		nameAndLength = 0;
		for (int i = 0; i < 3; i++) {
			nameAndLength = nameAndLength << 8;
			if (bytes.length > i) {
				nameAndLength = nameAndLength + bytes[i];
			}
		}
		nameAndLength = nameAndLength << 8;
		nameAndLength = nameAndLength + length;
	}
	
	/**
	 * 将String类型的type转换为short类型
	 * @param type
	 * @throws Exception
	 * @author acer 严浩强
	 */
	public void setTypeToDisk(String type) throws Exception {
		byte[] bytes = type.getBytes();
		if (bytes.length > 2) {
			throw new Exception("超过两个字节");
		}
		this.type = 0;
		for (int i = 0; i < 2; i++) {
			this.type = (short) (this.type << 8);
			if (bytes.length > i) {
				this.type = (short) (this.type + bytes[i]);
			}
		}
	}
	
	public String getTypeToDisk() {
		byte[] bytes = new byte[2];
		short type1 = type;
		for (int i = 1; i >= 0; i--) {
			bytes[i] = (byte) (type1 & 0xff);
			type1 = (short) (type1 >> 8);
		}
		return new String(bytes);
	}

}
